package com.yuncheng.shiro.authc.aop;

import com.alibaba.fastjson.JSON;
import com.yuncheng.common.api.AuthenticationAPI;
import com.yuncheng.constant.CommonConstant;
import com.yuncheng.shiro.authc.JwtToken;
import com.yuncheng.utils.I18nUtil;
import com.yuncheng.utils.SpringContextUtils;
import com.yuncheng.utils.ThreadContextHelper;
import com.yuncheng.vo.HttpResult;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;

/**
 * @Description: 鉴权登录拦截器
 **/
public class JwtFilter extends BasicHttpAuthenticationFilter {

    private static final Logger log = LoggerFactory.getLogger(JwtFilter.class);

    private boolean allowOrigin = true;

    public JwtFilter() {
    }

    public JwtFilter(boolean allowOrigin) {
        this.allowOrigin = allowOrigin;
    }

    /**
     * 执行登录认证
     *
     * @param request
     * @param response
     * @param mappedValue
     * @return
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        HttpServletResponse res = (HttpServletResponse)response;
        try {
            executeLogin(request, response);
            return true;
        } catch (Exception e) {
            // 两处改动，打包到了仓库，影响3.1.1和3.1.2，两版本的代码tag没有同步
            HttpServletResponse httpServletResponse = (HttpServletResponse) response;

            httpServletResponse.reset();
            httpServletResponse.setStatus(HttpStatus.UNAUTHORIZED.value());
            //设置编码格式
            httpServletResponse.setCharacterEncoding("UTF-8");

            HttpResult httpResult = HttpResult.error(HttpStatus.UNAUTHORIZED.value(), e.getMessage());
            res.setHeader("Access-Control-Allow-Origin", "*");
            try {
                PrintWriter pw = httpServletResponse.getWriter();
                pw.write(JSON.toJSONString(httpResult));
                pw.flush();
                pw.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            return false;
        }
    }

    /**
     *
     */
    @Override
    protected boolean executeLogin(ServletRequest request, ServletResponse response) {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        String token = httpServletRequest.getHeader(CommonConstant.X_ACCESS_TOKEN);
        if (token == null || token.equals("")) {
            throw new AuthenticationException(I18nUtil.message("token.is.null"));
        }
        JwtToken jwtToken = new JwtToken(token);

        // 提交给realm进行登入，如果错误他会抛出异常并被捕获
        getSubject(request, response).login(jwtToken);
        // 如果没有抛出异常则代表登入成功，返回true
        return true;
    }

    /**
     * 对跨域提供支持
     */
    @Override
    protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
//		HttpServletRequest httpServletRequest = (HttpServletRequest) request;
//		HttpServletResponse httpServletResponse = (HttpServletResponse) response;
//		httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin"));
//		httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
//		httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers"));
//		// 跨域时会首先发送一个option请求，这里我们给option请求直接返回正常状态
//		if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
//			httpServletResponse.setStatus(HttpStatus.OK.value());
//			return false;
//		}
//		return super.preHandle(request, response);

        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        if (allowOrigin) {
            httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin"));
            httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
            httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers"));
            // 是否允许发送Cookie，默认Cookie不包括在CORS请求之中。设为true时，表示服务器允许Cookie包含在请求中。
            httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true");

        }
        // 跨域时会首先发送一个option请求，这里我们给option请求直接返回正常状态
        if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
            httpServletResponse.setStatus(HttpStatus.OK.value());
            return false;
        }
        return super.preHandle(request, response);
    }

    @Override
    protected void postHandle(ServletRequest request, ServletResponse response) throws Exception {
        Map<String, AuthenticationAPI> authenticationAPIMap = SpringContextUtils.getApplicationContext().getBeansOfType(AuthenticationAPI.class);
        authenticationAPIMap.forEach((k, v) -> v.clear());
        ThreadContextHelper.clear();
    }
}
